/*
 * Copyright (c) 2018-2999 湖南洛云网络科技有限公司 All rights reserved.
 *
 * https://www.gz-yami.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.yami.shop.service.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yami.shop.bean.enums.BuyerReasonType;
import com.yami.shop.bean.model.Order;
import com.yami.shop.bean.param.OrderPayParam;
import com.yami.shop.bean.param.StatisticsRefundParam;
import com.yami.shop.common.i18n.I18nMessage;
import com.yami.shop.common.util.Arith;
import com.yami.shop.dao.OrderMapper;
import com.yami.shop.dao.OrderRefundMapper;
import com.yami.shop.service.OrderService;
import com.yami.shop.service.StatisticsOrderService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * @author lgh on 2018/09/15.
 */
@Service
@AllArgsConstructor
public class StatisticsOrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements StatisticsOrderService {

    private final OrderMapper orderMapper;

    private final OrderRefundMapper orderRefundMapper;

    @Override
    public OrderPayParam getPayUserCountByshopId(Long shopId, Date startTime, Date endTime) {
        OrderPayParam nowOrderPay = orderMapper.getOrderCountByShopId(shopId, startTime, endTime);
        StatisticsRefundParam refundParam = orderRefundMapper.getRefundByShopId(shopId, startTime, endTime);
        Double onePrice = (nowOrderPay.getPayUserCount() == 0) ? 0 : (Arith.div(nowOrderPay.getPayActualTotal(), nowOrderPay.getPayUserCount(), 2));
        if (nowOrderPay.getPayActualTotal() == null) {
            nowOrderPay.setPayActualTotal(0.00);
        }
        nowOrderPay.setOnePrice(onePrice)
                .setRefund(refundParam.getPayActualTotal());
        return nowOrderPay;
    }

    @Override
    public OrderPayParam getActualTotalByHour(Long shopId, Date startTime, Date endTime) {
        List<OrderPayParam> actualTotalByHour = orderMapper.getActualTotalByHour(shopId, startTime, endTime);
        Map<Integer, Double> payMap = new HashMap<>(30);
        for (OrderPayParam orderPay : actualTotalByHour) {
            payMap.put(Integer.parseInt(orderPay.getDates()), orderPay.getPayActualTotal());
        }
        List<OrderPayParam> yesterdayTotalByHour = orderMapper.getActualTotalByHour(shopId, DateUtil.beginOfDay(DateUtil.yesterday()),
                DateUtil.endOfDay(DateUtil.yesterday()));
        Map<Integer, Double> yesterdayPayMap = new HashMap<>(30);
        for (OrderPayParam orderPay : yesterdayTotalByHour) {
            yesterdayPayMap.put(Integer.parseInt(orderPay.getDates()), orderPay.getPayActualTotal());
        }
        double sum = 0.00;
        double yesterdaySum = 0.00;
        List<Double> payYesterdayActualTotal = new ArrayList<>();
        List<Double> nowActualTotal = new ArrayList<>();
        OrderPayParam param = new OrderPayParam();
        for (int i = 0; i < 24; i++) {
            if (payMap.get(i) != null) {
                sum = Arith.add(sum, payMap.get(i));
            }
            if (yesterdayPayMap.get(i) != null) {
                yesterdaySum = Arith.add(yesterdaySum, yesterdayPayMap.get(i));
            }
            payYesterdayActualTotal.add(Arith.round(yesterdaySum, 2));
            nowActualTotal.add(Arith.round(sum, 2));
        }
        param.setPayYesterdayActualTotal(payYesterdayActualTotal);
        param.setNowActualTotal(nowActualTotal);
        return param;
    }

    @Override
    public List<OrderPayParam> getActualTotalByDay(Long shopId, Date startTime, Date endTime) {
        List<OrderPayParam> actualTotal = orderMapper.getPayOrderByTime(shopId, startTime, endTime);
        List<OrderPayParam> actualTotalByDay = new ArrayList<>();
        //获取本月起始时间
        DateTime dateTime = DateUtil.beginOfMonth(DateUtil.date());
        double sum = 0.00;
        for (OrderPayParam orderPayParam : actualTotal) {
            DateTime time = DateTime.of(orderPayParam.getDates(), "yyyy-MM-dd");
            if (DateUtil.compare(time, dateTime) > 0) {
                sum = Arith.add(sum, orderPayParam.getPayActualTotal());
                orderPayParam.setOnePrice(Arith.round(sum, 2));
            }
            actualTotalByDay.add(orderPayParam);
        }
        return actualTotalByDay;
    }


    /**
     * 生成退款信息和比率信息
     *
     * @param shopId 商家id
     */
    @Override
    public StatisticsRefundParam getOrderRefundByShopId(Long shopId, Date startTime, Date endTime) {
        StatisticsRefundParam refundParam = orderRefundMapper.getRefundByShopId(shopId, startTime, endTime);
        OrderPayParam oderParam = getPayUserCountByshopId(shopId, startTime, endTime);
        StatisticsRefundParam yesterdayRefundParam = orderRefundMapper.getRefundByShopId(shopId, DateUtil.beginOfDay(DateUtil.yesterday()),
                DateUtil.endOfDay(DateUtil.yesterday()));
        OrderPayParam yesterdayOderParam = getPayUserCountByshopId(shopId, DateUtil.beginOfDay(DateUtil.yesterday()),
                DateUtil.endOfDay(DateUtil.yesterday()));
        StatisticsRefundParam lastWeekRefundParam = orderRefundMapper.getRefundByShopId(shopId, DateUtil.beginOfDay(DateUtil.lastWeek()),
                DateUtil.endOfDay(DateUtil.lastWeek()));
        OrderPayParam lastWeekOderParam = getPayUserCountByshopId(shopId, DateUtil.beginOfDay(DateUtil.lastWeek()),
                DateUtil.endOfDay(DateUtil.lastWeek()));
        double yesterdayRate = 0.00;
        double lastWeekRate = 0.00;
        double refundRate = 0.00;
        double yesterdayRefundRate = 0.00;
        double lastweekRefundRate = 0.00;
        //金额比率
        if (yesterdayRefundParam.getPayActualTotal() != 0) {
            yesterdayRate = Arith.div(Arith.mul(refundParam.getPayActualTotal(), 100), yesterdayRefundParam.getPayActualTotal(), 2);
        }
        if (lastWeekRefundParam.getPayActualTotal() != 0) {
            lastWeekRate = Arith.div(Arith.mul(refundParam.getPayActualTotal(), 100), lastWeekRefundParam.getPayActualTotal(), 2);
        }
        //退款比率
        if (oderParam.getPayOrderCount() != 0) {
            refundRate = Arith.div(Arith.mul(refundParam.getRefundCount(), 100), oderParam.getPayOrderCount(), 2);
        }
        if (yesterdayOderParam.getPayOrderCount() != 0) {
            yesterdayRefundRate = Arith.div(Arith.mul(refundParam.getRefundCount(), 100), yesterdayOderParam.getPayOrderCount(), 2);
        }
        if (lastWeekOderParam.getPayOrderCount() != 0) {
            lastweekRefundRate = Arith.div(Arith.mul(lastWeekRefundParam.getRefundCount(), 100), lastWeekOderParam.getPayOrderCount(), 2);
        }
        yesterdayRefundRate = Arith.sub(refundRate, yesterdayRefundRate);
        lastweekRefundRate = Arith.sub(refundRate, lastweekRefundRate);
        refundParam.setYesterdayAmountRate(yesterdayRate);
        refundParam.setSevenDayAmountRate(lastWeekRate);
        refundParam.setRefundRate(refundRate);
        refundParam.setYesterdayRefundRate(yesterdayRefundRate);
        refundParam.setSevenDayRefundRate(lastweekRefundRate);
        return refundParam;
    }


    /**
     * 生成退款信息和分段比率信息
     *
     * @param shopId 商家id
     */
    @Override
    public List<StatisticsRefundParam> getOrderRefundByShopIdAndDay(Long shopId, Date startTime, Date endTime) {
        List<StatisticsRefundParam> refundList = orderRefundMapper.getRefundByShopIdAndDay(shopId, startTime, endTime);
        List<OrderPayParam> orderList = orderMapper.getPayOrderByTime(shopId, startTime, endTime);
        List<StatisticsRefundParam> refundNewList = new ArrayList<>();
        for (int i = 0; i < refundList.size(); i++) {
            StatisticsRefundParam refundParam = refundList.get(i);
            if (i + 1 > orderList.size()) {
                break;
            }
            OrderPayParam orderParam = orderList.get(i);
            double rate = 0.00;
            if (orderParam.getPayOrderCount() != 0) {
                rate = Arith.div(Arith.mul(refundParam.getRefundCount(), 100), orderParam.getPayOrderCount(), 2);

            } else if (refundParam.getRefundCount() != 0) {
                rate = 100.00;
            }

            refundParam.setRefundRate(rate);
            refundList.set(i, refundParam);
            refundParam.setRefundDateToString(DateUtil.formatDate(refundParam.getRefundDate()));
            refundNewList.add(refundParam);

        }
        return refundNewList;
    }

    /**
     * 根据商品名生成退款排行
     *
     * @param shopId 商家id
     */
    @Override
    public List<StatisticsRefundParam> getRefundRankingByProd(Long shopId, Date beginTime, Date endTime) {
        return orderRefundMapper.getRefundRankingByProd(shopId, beginTime, endTime,I18nMessage.getDbLang());
    }

    /**
     * 根据退款原因生成退款排行
     *
     * @param shopId 商家id
     */
    @Override
    public List<StatisticsRefundParam> getRefundRankingByReason(Long shopId, Date beginTime, Date endTime) {
        List<StatisticsRefundParam> ranking = orderRefundMapper.getRefundRankingByReason(shopId, beginTime, endTime);
        List<StatisticsRefundParam> rank = new ArrayList<>();
        double sum = 0.00;
        for (StatisticsRefundParam refundParam : ranking) {
            sum = Arith.add(sum, refundParam.getPayActualTotal());
        }
        for (StatisticsRefundParam refundParam : ranking) {
            try {
                BuyerReasonType reasonType = BuyerReasonType.instance(Integer.valueOf(refundParam.getBuyerReason()));
                if (Objects.nonNull(reasonType)) {
                    refundParam.setBuyerReason(I18nMessage.getDbLang() == 0 ? reasonType.getCn() : reasonType.getEn());
                }
            } catch (NumberFormatException ignored) {
                //如果出现BuyerReasonType没有的类型，则默认即可
            }
            refundParam.setRefundRate(Arith.div(Arith.mul(refundParam.getPayActualTotal(), 100), sum, 2));
            rank.add(refundParam);
        }
        return rank;
    }

}
